﻿using System;
using Evolution.Application.SharedKernel.Actions.Authorisation;
using Evolution.Application.SharedKernel.Tests.Core.Actions.Helpers;
using Evolution.Sdk.Container;
using Evolution.Sdk.Unity;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;

namespace Evolution.Client.ImportData.Infrastructure
{
    public abstract class ImportInfrastructure
    {
        protected TestUserContextHelper UserContextHelper { get; set; }

        /// <summary>
        /// Unity container variable
        /// </summary>
        protected IUnityContainer UnityContainer { get; set; }

        /// <summary>
        /// Resolves dependencies and provides instantiated objects to work with.
        /// </summary>
        protected UnityContainerAdapter DependencyResolver { get; set; }

        #region Initialise Import Configuration
        /// <summary>
        /// Initialise the required Unity configuration for running integration tests before each test
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Initialise")]
        public virtual void InitialiseUnityConfiguration()
        {
            InitialiseBootstrapper();
            InitialiseMockDependencyBootstrapper();
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        private void InitialiseMockDependencyBootstrapper()
        {
            // Set the default Session Id
            this.UserContextHelper = new TestUserContextHelper();
            this.UserContextHelper.SetScopeId(Guid.NewGuid());
            var userInformation = Rhino.Mocks.MockRepository.GenerateMock<IUserInformation>();
            Rhino.Mocks.RhinoMocksExtensions
                .Expect(userInformation, userInfo => userInfo.ClientAccountId)
                .Return(new Guid("00000000-0000-0000-0000-000000000001"));
            Rhino.Mocks.RhinoMocksExtensions
                .Expect(userInformation, userInfo => userInfo.OrganisationLinkId)
                .Return(new Guid("00000000-0000-0000-0000-000000000003"));
            this.UserContextHelper.SetUserInformation(userInformation);
        }

        /// <summary>
        /// Initialises the test bootstrapper
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Initialise")]
        protected virtual void InitialiseBootstrapper()
        {
            // Initialise the container
            this.UnityContainer = new UnityContainer();

            // Load configuration file based unity configurations
            this.UnityContainer.LoadConfiguration();

            this.DependencyResolver = new UnityContainerAdapter(UnityContainer);

            this.UnityContainer.RegisterInstance<IRegisterDependencies>(this.DependencyResolver);
            this.UnityContainer.RegisterInstance<IResolveDependencies>(this.DependencyResolver);

            // Run default wireup, if there is one
            if (this.UnityContainer.IsRegistered<IWireUpDependencies>())
            {
                var wireup = this.UnityContainer.Resolve<IWireUpDependencies>();
                wireup.WireUp();
            }

            // Run named wireups, if there are any
            var wireups = this.UnityContainer.ResolveAll<IWireUpDependencies>();

            foreach (var wireup in wireups)
            {
                wireup.WireUp();
            }

            var bootstrapper = this.GetActionsDependencyBootstrapper();
            bootstrapper.WireUp();
            bootstrapper.VerifyDependencies();
        }
        #endregion

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        protected abstract Application.SharedKernel.Actions.Bootstrappers.ActionsDependencyBootstrapper GetActionsDependencyBootstrapper();

        /// <summary>
        /// Gets an instance of <typeparamref name="T"/>
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> to resolve</typeparam>
        protected T Resolve<T>(params ResolverOverride[] overrides)
        {
            return this.UnityContainer.Resolve<T>(overrides);
        }

        /// <summary>
        /// Gets an instance of <typeparamref name="T"/> as located by the provided <paramref name="name"/>
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> to resolve</typeparam>
        protected T Resolve<T>(string name, params ResolverOverride[] overrides)
        {
            return this.UnityContainer.Resolve<T>(name, overrides);
        }
    }
}
